﻿/*CLR Version: 4.0.30319.18063
 * Creat Date: 2016/6/27 10:26:02
 * Creat Year: 2016
 * Creator: 程炜.Snail
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using Utility.Extensions;
using System.Threading;
namespace Utility.DBUtility
{
    /// <summary>
    /// 自动将DATASET中数据通过反射转换成List[T]或 Model 方式返回
    /// 需要转换的DataSet Table 名称与Model中名称相同
    /// 需要 DataTable 的列名与 Model 中字段名称 相同(可以忽略大小写)
    /// Snail 2011-11-16
    /// 2012-06-07 使用泛型返回數據
    /// 2012-09-24 添加数据转换成 Dictionary[TKey, TValue]
    /// </summary>
    public static class DataSet2Object
    {
        /// <summary>
        /// DataTable 扩展方法, 返回List[T]
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<T> ToList<T>(this DataTable dt)
        {
            return DataToList<T>(dt);
        }
        /// <summary>
        /// DataTable 扩展方法, 返回数据的Json格式List
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="timeFormat"></param>
        /// <returns></returns>
        public static string ToJsonList(this DataTable dt,string timeFormat ="yyyy-MM-dd HH:mm:ss")
        {
            return DataToJsonList(dt, timeFormat);
        }
        /// <summary>
        /// 通过 DataSet 返回 List[T] 集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static string DataToJsonList(this DataSet ds)
        {
            if (null == ds || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
            {
                return "[]";
            }
            return DataToJsonList(ds.Tables[0]);
        }
        /// <summary>
        /// 通过DataTable 返回 json数据
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="timeFormat"></param>
        /// <returns></returns>
        public static string DataToJsonList(this DataTable dt, string timeFormat = "yyyy-MM-dd HH:mm:ss")
        {
            if (null == dt || dt.Rows.Count == 0)
            {
                return "[]";
            }
            StringBuilder strBuilder = new StringBuilder();

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                if (strBuilder.Length > 0)
                {
                    strBuilder.Append(",");
                }
                strBuilder.Append(DataToJsonObj(dt.Rows[i], timeFormat));
            }
            strBuilder.Insert(0, "[");
            strBuilder.Append("]");
            return strBuilder.ToString();
        }
        /// <summary>
        /// 根据DataRow创建 T类型对象 并且返回
        /// </summary>
        /// <param name="dr"></param>
        /// <param name="timeFormat"></param>
        /// <returns></returns>
        public static string DataToJsonObj(DataRow dr, string timeFormat = "yyyy-MM-dd HH:mm:ss")
        {
            if (null == dr)
            {
                return string.Empty;
            }
            StringBuilder strBuilder = new StringBuilder();
            for (int i = 0; i < dr.Table.Columns.Count; i++)
            {
                if (strBuilder.Length > 0)
                {
                    strBuilder.Append(",");
                }
                strBuilder.AppendFormat("\"{0}\":", dr.Table.Columns[i].ColumnName);
                if (DBNull.Value != dr[i] && string.Empty != dr[i].ToString())
                {
                    var dataType = dr.Table.Columns[i].DataType;
                    if (dataType == typeof(String))
                    {
                        strBuilder.AppendFormat("\"{0}\"", Convert.ToString(dr[i]).Trim());
                    }
                    else if (dataType == typeof(int) || dataType == typeof(int?) || dataType == typeof(Nullable<int>)
                           || dataType == typeof(double) || dataType == typeof(double?) || dataType == typeof(Nullable<double>)
                           || dataType == typeof(decimal) || dataType == typeof(decimal?) || dataType == typeof(Nullable<decimal>)
                           || dataType == typeof(short) || dataType == typeof(short?) || dataType == typeof(Nullable<short>)
                           || dataType == typeof(byte) || dataType == typeof(byte?) || dataType == typeof(Nullable<byte>)
                           || dataType == typeof(long) || dataType == typeof(long?) || dataType == typeof(Nullable<long>))
                    {
                        strBuilder.AppendFormat("{0}", Convert.ToString(dr[i]));
                    }
                    else if (dataType == typeof(DateTime) || dataType == typeof(DateTime?) || dataType == typeof(Nullable<DateTime>))
                    {
                        strBuilder.AppendFormat("\"{0}\"", Convert.ToDateTime(dr[i]).ToString(timeFormat));
                    }
                    else if (dataType == typeof(bool) || dataType == typeof(bool?) || dataType == typeof(Nullable<bool>)
                            || dataType == typeof(Boolean) || dataType == typeof(Boolean?) || dataType == typeof(Nullable<Boolean>))
                    {
                        strBuilder.AppendFormat("{0}", Convert.ToBoolean(dr[i]).ToString().ToLower());
                    }
                    else
                    {
                        strBuilder.AppendFormat("\"{0}\"", Convert.ToString(dr[i]));
                    }
                }
                else
                {
                    strBuilder.Append("null");
                }
            }
            strBuilder.Insert(0,"{");
            strBuilder.Append("}");
            return strBuilder.ToString();
        }
        /// <summary>
        /// DataSet 扩展方法, 返回List[T]
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static List<T> ToList<T>(this DataSet ds)
        {
            return DataToList<T>(ds);
        }
        /// <summary>
        /// 通过 DataTable 返回 List[T] 集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<T> DataToList<T>(DataTable dt)
        {
            if (null == dt || dt.Rows.Count == 0)
            {
                return new List<T>();
            }

            List<T> list = new List<T>();

            //if (dt.Rows.Count > 10000)
            //{
            //    ConcurrentBag<T> bags = new ConcurrentBag<T>();
            //    ParallelOptions op = new ParallelOptions();
            //    op.MaxDegreeOfParallelism = 10;
            //    Parallel.ForEach(dt.AsEnumerable(), op, (item, loopState) =>
            //     {
            //         bags.Add(DataToObj<T>(item));
            //     });
            //    list = bags.ToList();
            //}
            //else
            //{
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    T obj = DataToObj<T>(dt.Rows[i]);
                    if (null != obj)
                    {
                        list.Add(obj);
                    }
                }
            //}
            return list;
        }
        /// <summary>
        /// 通过 DataSet 返回 List[T] 集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static List<T> DataToList<T>(DataSet ds)
        {
            if (null == ds || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
            {
                return new List<T>();
            }
            return DataToList<T>(ds.Tables[0]);
        }
        /// <summary>
        /// 根据DataSet 返回一个 T类型对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static T DataToObj<T>(DataTable dt)
        {
            if (null == dt || dt.Rows.Count == 0)
            {
                return default(T);
            }
            return DataToObj<T>(dt.Rows[0]);
        }
        /// <summary>
        /// 根据DataSet 返回一个 T类型对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static T DataToObj<T>(DataSet ds)
        {
            if (null == ds || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
            {
                return default(T);
            }
            return DataToObj<T>(ds.Tables[0].Rows[0]);
        }
        /// <summary>
        /// DataTable 扩展方法, 返回[T]
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static T ToModel<T>(this DataSet ds)
        {
            return DataToObj<T>(ds);
        }
        /// <summary>
        /// DataRow 扩展方法, 返回[T]
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static T ToModel<T>(this DataRow dr)
        {
            return DataToObj<T>(dr);
        }
        /// <summary>
        /// DataTable 扩展方法, 返回[T]
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ds"></param>
        /// <returns></returns>
        public static T ToModel<T>(this DataTable dt)
        {
            if (null == dt || dt.Rows.Count == 0)
            {
                return default(T);
            }
            return DataToObj<T>(dt.Rows[0]);
        }
        /// <summary>
        /// 根据DataRow创建 T类型对象 并且返回
        /// </summary>
        /// <param name="dr"></param>
        /// <returns></returns>
        public static T DataToObj<T>(DataRow dr)
        {
            if (null == dr)
            {
                return default(T);
            }
            Type tp = typeof(T);

            if ((tp == typeof(String))
                || (tp == typeof(int) || tp == typeof(int?) || tp == typeof(Nullable<int>))
                || (tp == typeof(double) || tp == typeof(double?) || tp == typeof(Nullable<double>))
                || (tp == typeof(DateTime) || tp == typeof(DateTime?) || tp == typeof(Nullable<DateTime>))
                || (tp == typeof(decimal) || tp == typeof(decimal?) || tp == typeof(Nullable<decimal>))
                || (tp == typeof(short) || tp == typeof(short?) || tp == typeof(Nullable<short>))
                || (tp == typeof(byte) || tp == typeof(byte?) || tp == typeof(Nullable<byte>))
                || (tp == typeof(long) || tp == typeof(long?) || tp == typeof(Nullable<long>))
                )//对简单类型进行判断            
            {
                if (DBNull.Value != dr[0] && string.Empty != dr[0].ToString()) //不为空
                {
                    return (T)Convert.ChangeType(dr[0], typeof(T));
                }
                else
                {
                    return default(T);
                }
            }

            T obj = (T)Assembly.Load(tp.Assembly.FullName).CreateInstance(tp.FullName);
            Type typeObj = obj.GetType();

            for (int i = 0; i < dr.Table.Columns.Count; i++)
            {
                //BindingFlags.Public | BindingFlags.IgnoreCase 需要反射的内容是 Public 以及 忽略大小写  以及搜索的范围为当前实例
                System.Reflection.PropertyInfo propertyInfo = typeObj.GetProperty(dr.Table.Columns[i].ColumnName, BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance);
                if (null == propertyInfo)
                {
                    continue;
                }
                if (DBNull.Value != dr[i] && string.Empty != dr[i].ToString())
                {
                    if (propertyInfo.PropertyType.IsEnum)
                    {
                        propertyInfo.SetValue(obj, Enum.ToObject(propertyInfo.PropertyType, dr[i]), null);
                    }
                    else
                    {
                        //出现频率最高的放在前面，减少比较次数
                        if (propertyInfo.PropertyType == typeof(String))
                        {
                            propertyInfo.SetValue(obj, Convert.ToString(dr[i]), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(int) || propertyInfo.PropertyType == typeof(int?) || propertyInfo.PropertyType == typeof(Nullable<int>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToInt32(dr[i]), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(double) || propertyInfo.PropertyType == typeof(double?) || propertyInfo.PropertyType == typeof(Nullable<double>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToDouble(Convert.ToDecimal(dr[i])), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(DateTime) || propertyInfo.PropertyType == typeof(DateTime?) || propertyInfo.PropertyType == typeof(Nullable<DateTime>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToDateTime(dr[i]), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(decimal) || propertyInfo.PropertyType == typeof(decimal?) || propertyInfo.PropertyType == typeof(Nullable<decimal>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToDecimal(dr[i]), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(short) || propertyInfo.PropertyType == typeof(short?) || propertyInfo.PropertyType == typeof(Nullable<short>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToInt16(dr[i]), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(byte) || propertyInfo.PropertyType == typeof(byte?) || propertyInfo.PropertyType == typeof(Nullable<byte>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToByte(dr[i]), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(long) || propertyInfo.PropertyType == typeof(long?) || propertyInfo.PropertyType == typeof(Nullable<long>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToInt64(dr[i]), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(bool) || propertyInfo.PropertyType == typeof(bool?) || propertyInfo.PropertyType == typeof(Nullable<bool>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToBoolean(dr[i]), null);
                        }
                        else if (propertyInfo.PropertyType == typeof(Boolean) || propertyInfo.PropertyType == typeof(Boolean?) || propertyInfo.PropertyType == typeof(Nullable<Boolean>))
                        {
                            propertyInfo.SetValue(obj, Convert.ToBoolean(dr[i]), null);
                        }    
                        else
                        {
                            propertyInfo.SetValue(obj, dr[i], null);
                        }
                    }
                }
            }
            return obj;
        }

        /// <summary>
        /// DataSet 转换成 Dictionary[TKey, TValue]
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="ds">DataSet</param>
        /// <param name="columnName">作为Tkey的列名</param>
        /// <returns></returns>
        public static Dictionary<TKey, TValue> DataToDictionary<TKey, TValue>(this DataSet ds, string columnName)
        {
            if (null == ds || ds.Tables.Count == 0 || ds.Tables[0].Rows.Count == 0)
            {
                return new Dictionary<TKey, TValue>();
            }
            return DataToDictionary<TKey, TValue>(ds.Tables[0], columnName);
        }
        /// <summary>
        /// DataTable 转换成 Dictionary[TKey, TValue]
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="dt">DataTable</param>
        /// <param name="columnName">作为Tkey的列名</param>
        /// <returns></returns>
        public static Dictionary<TKey, TValue> DataToDictionary<TKey, TValue>(this DataTable dt, string columnName)
        {
            if (null == dt || dt.Rows.Count == 0)
            {
                return new Dictionary<TKey, TValue>();
            }

            Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>();

            for (int i = 0; i < dt.Rows.Count; i++)
            {
                TValue obj = DataToObj<TValue>(dt.Rows[i]);
                if (null != obj)
                {
                    TKey key = (TKey)dt.Rows[i][columnName];
                    try
                    {
                        dictionary.Add(key, obj);
                    }
                    catch//如果说出现异常,则将相同的KEY对象替换
                    {
                        dictionary[key] = obj;
                    }
                }
            }
            return dictionary;
        }
        
        #region List转DataTable melon
        /// <summary>
        /// 将T类型的list对象转换成DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static DataTable ToDataTable<T>(IList<T> list)
        {
            DataTable table = CreateDataTable<T>();
            Type entityType = typeof(T);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);
            if (null == list || list.Count == 0)
            {
                return table;
            }
            foreach (T item in list)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                {
                    row[prop.Name] = prop.GetValue(item) == null ? DBNull.Value : prop.GetValue(item);
                }
                table.Rows.Add(row);
            }
            return table;
        }
        /// <summary>
        /// 根据T类型创建空的DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static DataTable CreateDataTable<T>()
        {
            Type entityType = typeof(T);
            DataTable table = new DataTable(entityType.Name);
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);
            foreach (PropertyDescriptor prop in properties)
            {
                Type conversionType = prop.PropertyType;
                if (conversionType.IsNullableType())
                {
                    conversionType = conversionType.GetUnNullableType();
                }
                table.Columns.Add(prop.Name, conversionType);
            }
            return table;
        }   
        #endregion

    }
}
